package org.fujene.memoryblock.dictionary;

import java.nio.ByteBuffer;
import org.fujene.constants.Constants;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class DictionaryBlock extends MemoryBlock{
	public static final int OPT_LEN = 0;
	public static final int OPT_TYPES = 1;
	public static final int OPTSIZE = 2;

	public DictionaryBlock(ByteBuffer block, int bodySize, int ID, int cluster){
		super(block, bodySize, ID, Constants.MEMORY_TYPE_DICT, cluster);
		this.optionSize = OPTSIZE;
	}

	public DictionaryBlock(ByteBuffer existingBody){
		super(existingBody);
	}

	// Reading \\
	public DictionaryPackage readAll(int ptr){
		DictionaryPackage pkg = DictionaryPackage.setPackage(option[OPT_TYPES], getID(), ptr);
		pkg.next(getPointer(ptr, PTR));
		ptr += PTR;
		pkg.freq(getInt(ptr, DOCFREQ));
		ptr += DOCFREQ;
		for(int i = 0; i < option[OPT_TYPES]; i++){
			pkg.invIndex(getPointer(ptr, PTR), i);
			ptr += PTR;
		}
		int termlen = getInt(ptr, STRLEN);
		ptr += STRLEN;
		pkg.nameraw(read(ptr, termlen));

		return pkg;
	}

	public LookupPointer readNextPointer(int ptr){
		LookupPointer result = getPointer(ptr, PTR);
		if(result == null) return null;
		return result.withCluster(getCluster());
	}

	public LookupPointer readInvIndex(int ptr, int index){
		if(index >= option[OPT_TYPES]) return null;
		ptr += PTR + DOCFREQ + (index * PTR);
		LookupPointer result = getPointer(ptr, PTR);
		if(result == null) return null;
		return result;
	}

	// Writing \\
	public int writeAll(int ptr, DictionaryPackage pkg){
		pkg.current(LookupPointer.valueOf(getID(), ptr));
		setPointer(ptr, PTR, pkg.getNext());
		ptr += PTR;
		setInt(ptr, DOCFREQ, pkg.getFrequency());
		ptr += DOCFREQ;
		for(int i = 0; i < option[OPT_TYPES]; i++){
			setPointer(ptr, PTR, pkg.getInvertIndex(i));
			ptr += PTR;
		}
		setInt(ptr, STRLEN, pkg.getNameLength());
		ptr += STRLEN;
		store(pkg.getNameRaw(), ptr);

		option[OPT_LEN]++;

		return pkg.length();
	}

	public void writeNextPointer(int ptr, LookupPointer next){
		setPointer(ptr, PTR, next);
	}

	public int incrementDocFreq(int ptr){
		ptr += PTR;
		int docfreq = getInt(ptr, DOCFREQ);
		setInt(ptr, DOCFREQ, docfreq + 1);
		return docfreq + 1;
	}

	public void writeInvertIndex(int ptr, int index, LookupPointer inv){
		if(index >= option[OPT_TYPES]) return;
		ptr += PTR + DOCFREQ + (index * PTR);
		setPointer(ptr, PTR, inv);
	}

	// reserve new pointer
	public synchronized int getNewPointer(DictionaryPackage pkg){
		if(this.bodyVacancy < pkg.length()) return -1;
		this.bodyVacancy -= pkg.length();
		return this.bodySize - this.bodyVacancy - pkg.length();
	}

	@Override
	public int getOptionSize(){
		return OPTSIZE;
	}

	@Override
	public byte[] getOptionByteStream(){
		byte[] form = new byte[4 * OPTSIZE];
		for(int i = 0; i < OPTSIZE; i++)
			System.arraycopy(ByteConverter.intToByte(option[i], 4), 0, form, 4 * i, 4);
		return form;
	}

	public int getTermCount(){
		return option[OPT_LEN];
	}

	@Override
	public int getOption(int num){
		if(num >= OPTSIZE) return -1;
		return option[num];
	}

	@Override
	public void setOption(int index, int value){
		if(index >= OPTSIZE) return;
		option[index] = value;
	}

	@Override
	public String getClassName(){
		return new String("Dictionary");
	}
}
